"""
Interface validation utilities for continual learning components.

This module provides helper functions and classes to validate that
implementations correctly adhere to their interfaces, improving reliability
and making interface violations easier to detect.
"""

from typing import Any, Type, Dict, Set
import inspect
import logging

from continuallearning.interfaces.models.pefts import (
    HookInterface,
    HookManagerInterface,
    HookBasedAdapterInterface,
    AdapterInterface,
)

logger = logging.getLogger(__name__)


class InterfaceValidationError(Exception):
    """Exception raised when an interface validation fails."""

    pass


class InterfaceValidator:
    """
    Validates that objects properly implement their interfaces.

    This utility class helps ensure that classes correctly implement
    the interfaces they claim to support, checking for required methods
    and properties according to SOLID principles.
    """

    @staticmethod
    def _get_required_members(interface_cls: Type) -> Dict[str, Set[str]]:
        """
        Extract required abstract methods and properties from an interface.

        Args:
            interface_cls: The interface class to extract from

        Returns:
            Dict with 'methods' and 'properties' as keys mapping to sets of required names
        """
        required = {"methods": set(), "properties": set()}

        # Get all abstract methods and properties
        for name, member in inspect.getmembers(interface_cls):
            if name.startswith("_") and name != "__enter__" and name != "__exit__":
                continue

            # Check if it's an abstract method
            if hasattr(member, "__isabstractmethod__") and getattr(
                member, "__isabstractmethod__"
            ):
                if isinstance(member, property):
                    required["properties"].add(name)
                else:
                    required["methods"].add(name)

        return required

    @staticmethod
    def validate_adapter(adapter: Any) -> bool:
        """
        Validate that an object implements AdapterInterface correctly.

        Args:
            adapter: The object to validate

        Returns:
            bool: True if validation passes

        Raises:
            InterfaceValidationError: If validation fails
        """
        if not isinstance(adapter, AdapterInterface):
            raise InterfaceValidationError(
                f"Object {adapter.__class__.__name__} does not implement AdapterInterface"
            )

        required = InterfaceValidator._get_required_members(AdapterInterface)

        # Check required properties
        for prop_name in required["properties"]:
            if not hasattr(adapter, prop_name):
                raise InterfaceValidationError(
                    f"Missing required property '{prop_name}' in {adapter.__class__.__name__}"
                )

        # Check required methods
        for method_name in required["methods"]:
            if not hasattr(adapter, method_name) or not callable(
                getattr(adapter, method_name)
            ):
                raise InterfaceValidationError(
                    f"Missing required method '{method_name}' in {adapter.__class__.__name__}"
                )

        return True

    @staticmethod
    def validate_hook_interface(hook: Any) -> bool:
        """
        Validate that an object implements HookInterface correctly.

        Args:
            hook: The object to validate

        Returns:
            bool: True if validation passes

        Raises:
            InterfaceValidationError: If validation fails
        """
        if not isinstance(hook, HookInterface):
            raise InterfaceValidationError(
                f"Object {hook.__class__.__name__} does not implement HookInterface"
            )

        required = InterfaceValidator._get_required_members(HookInterface)

        # Check required properties
        for prop_name in required["properties"]:
            if not hasattr(hook, prop_name):
                raise InterfaceValidationError(
                    f"Missing required property '{prop_name}' in {hook.__class__.__name__}"
                )

        # Check required methods
        for method_name in required["methods"]:
            if not hasattr(hook, method_name) or not callable(
                getattr(hook, method_name)
            ):
                raise InterfaceValidationError(
                    f"Missing required method '{method_name}' in {hook.__class__.__name__}"
                )

        return True

    @staticmethod
    def validate_hook_manager(manager: Any) -> bool:
        """
        Validate that an object implements HookManager correctly.

        Args:
            manager: The object to validate

        Returns:
            bool: True if validation passes

        Raises:
            InterfaceValidationError: If validation fails
        """
        if not isinstance(manager, HookManagerInterface):
            raise InterfaceValidationError(
                f"Object {manager.__class__.__name__} does not implement HookManager"
            )

        required = InterfaceValidator._get_required_members(HookManagerInterface)

        # Check required properties
        for prop_name in required["properties"]:
            if not hasattr(manager, prop_name):
                raise InterfaceValidationError(
                    f"Missing required property '{prop_name}' in {manager.__class__.__name__}"
                )

        # Check required methods
        for method_name in required["methods"]:
            if not hasattr(manager, method_name) or not callable(
                getattr(manager, method_name)
            ):
                raise InterfaceValidationError(
                    f"Missing required method '{method_name}' in {manager.__class__.__name__}"
                )

        return True

    @staticmethod
    def validate_hook_based_adapter(adapter: Any) -> bool:
        """
        Validate that an object implements HookBasedAdapterInterface correctly.

        Args:
            adapter: The object to validate

        Returns:
            bool: True if validation passes

        Raises:
            InterfaceValidationError: If validation fails
        """
        if not isinstance(adapter, HookBasedAdapterInterface):
            raise InterfaceValidationError(
                f"Object {adapter.__class__.__name__} does not implement HookBasedAdapterInterface"
            )

        # First validate the AdapterInterface methods
        InterfaceValidator.validate_adapter(adapter)

        # Then validate the hook-specific methods
        required = InterfaceValidator._get_required_members(HookBasedAdapterInterface)

        # Check required methods
        for method_name in required["methods"]:
            # Skip methods already checked in AdapterInterface
            if method_name in [
                "forward",
                "prepare_task",
                "get_trainable_parameters",
                "set_task",
            ]:
                continue

            if not hasattr(adapter, method_name) or not callable(
                getattr(adapter, method_name)
            ):
                raise InterfaceValidationError(
                    f"Missing required method '{method_name}' in {adapter.__class__.__name__}"
                )

        return True
